# -*- coding: utf-8 -*-
"""
智慧职教MOOC视频下载器 - 翻页管理模块
负责处理多页面的课程导航和页面跳转
"""

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import time
import re
from typing import List, Tuple, Optional, Dict, Any
from config import config
from logger import logger
from exceptions import PaginationError, PageLoadTimeoutError


class PaginationManager:
    """分页管理器，处理多页面的课程导航和页面跳转"""
    
    def __init__(self, driver):
        self.driver = driver
        self._current_page = 1
        self._total_pages = 1
        self._last_update_time = 0
    
    def get_courses_from_current_page(self) -> List[Dict[str, Any]]:
        """获取当前页面的所有课程信息"""
        courses_info = []
        try:
            logger.progress("正在获取当前页面的课程列表...")
            
            # 等待页面加载
            self._wait_for_course_list_load()
            
            # 获取课程信息
            course_list = self.driver.find_elements(By.CSS_SELECTOR, ".class-list .class-row")
            logger.info(f"当前页面找到 {len(course_list)} 门课程")
            
            for idx, course in enumerate(course_list, 1):
                try:
                    course_info = self._extract_course_info(course, idx)
                    if course_info:
                        courses_info.append(course_info)
                        logger.debug(f"  课程 {idx}: {course_info['course_name']} - {course_info['class_name']}")
                    
                except Exception as e:
                    logger.warning(f"课程信息解析失败 (第{idx}个): {e}")
                    
        except Exception as e:
            logger.error(f"获取课程列表失败: {e}")
            raise PaginationError(f"无法获取课程列表: {e}")
        
        return courses_info
    
    def _wait_for_course_list_load(self, timeout: int = 15):
        """等待课程列表加载完成"""
        try:
            WebDriverWait(self.driver, timeout).until(
                EC.presence_of_element_located((By.CLASS_NAME, "class-list"))
            )
            # 额外等待，确保所有课程都加载完成
            time.sleep(2)
        except TimeoutException:
            raise PageLoadTimeoutError(f"课程列表加载超时 ({timeout}秒)")
    
    def _extract_course_info(self, course_element, idx: int) -> Optional[Dict[str, Any]]:
        """从课程元素中提取课程信息"""
        try:
            course_name = course_element.find_element(By.CSS_SELECTOR, ".course-name").text.strip()
            class_name = course_element.find_element(By.CSS_SELECTOR, ".class-name").text.strip()
            
            # 提取教师姓名（通常在class_name的最后）
            teacher = self._extract_teacher_name(class_name)
            
            # 获取课程链接
            course_link = self._extract_course_link(course_element)
            
            return {
                'idx': idx,
                'course_name': course_name,
                'class_name': class_name,
                'teacher': teacher,
                'course_link': course_link
            }
            
        except NoSuchElementException as e:
            logger.warning(f"课程元素缺失: {e}")
            return None
    
    def _extract_teacher_name(self, class_name: str) -> str:
        """从班级名称中提取教师姓名"""
        if not class_name:
            return ""
        
        # 常见的教师姓名提取模式
        parts = class_name.split()
        if len(parts) > 1:
            # 假设最后一个部分是教师姓名
            return parts[-1]
        
        # 其他提取逻辑可以在这里添加
        return ""
    
    def _extract_course_link(self, course_element) -> str:
        """提取课程链接"""
        try:
            learn_btn = course_element.find_element(By.XPATH, ".//a[contains(text(), '课程学习')]")
            return learn_btn.get_attribute('href') or ""
        except NoSuchElementException:
            return ""

    def get_pagination_info(self) -> Tuple[int, int, List[Tuple[int, Any]]]:
        """获取分页信息
        
        Returns:
            Tuple[总页数, 当前页数, 页面链接列表]
        """
        try:
            logger.debug("正在获取分页信息...")
            
            # 检查是否有分页
            pagination = self.driver.find_elements(By.CSS_SELECTOR, "#page-box .pg-link")
            if not pagination:
                self._total_pages = 1
                self._current_page = 1
                logger.info("无分页，只有一页")
                return 1, 1, []
            
            # 获取当前页
            current_page = self._get_current_page_number()
            
            # 获取所有页面链接（排除前进后退按钮）
            page_links = []
            total_pages = 1
            
            for link in pagination:
                page_info = self._extract_page_info(link)
                if page_info:
                    page_num, link_element = page_info
                    page_links.append((page_num, link_element))
                    total_pages = max(total_pages, page_num)
            
            # 更新内部状态
            self._total_pages = total_pages
            self._current_page = current_page
            
            logger.info(f"分页信息: 当前第 {current_page} 页，总共 {total_pages} 页")
            return total_pages, current_page, page_links
            
        except Exception as e:
            logger.error(f"获取分页信息失败: {e}")
            return 1, 1, []
    
    def _extract_page_info(self, link_element) -> Optional[Tuple[int, Any]]:
        """从分页链接中提取页面信息"""
        try:
            link_text = link_element.get_attribute('onclick')
            if link_text and 'selectAllCourseFromStudent(' in link_text:
                # 提取页面号
                match = re.search(r'selectAllCourseFromStudent\((\d+)\)', link_text)
                if match:
                    page_num = int(match.group(1))
                    return page_num, link_element
        except Exception as e:
            logger.debug(f"提取页面信息失败: {e}")
        
        return None

    def navigate_to_page(self, page_num: int, max_retries: int = 3) -> bool:
        """跳转到指定页面"""
        if page_num == self._current_page:
            logger.debug(f"已在第{page_num}页，无需跳转")
            return True
        
        logger.progress(f"正在导航到第 {page_num} 页...")
        
        for attempt in range(max_retries):
            try:
                if attempt > 0:
                    logger.debug(f"第 {attempt + 1} 次尝试跳转...")
                
                # 确保页面完全加载
                self._wait_for_page_ready(max_wait=10)
                
                # 尝试多种跳转方法
                success = (
                    self._try_javascript_navigation(page_num) or
                    self._try_click_navigation(page_num) or
                    self._try_refresh_and_navigate(page_num)
                )
                
                if success:
                    self._current_page = page_num
                    logger.success(f"成功跳转到第 {page_num} 页")
                    return True
                else:
                    logger.warning(f"第 {attempt + 1} 次跳转失败")
                    
            except Exception as e:
                logger.warning(f"第 {attempt + 1} 次跳转异常: {e}")
            
            if attempt < max_retries - 1:
                time.sleep(2)  # 重试前等待
        
        logger.error(f"跳转到第 {page_num} 页失败（已重试 {max_retries} 次）")
        return False
    
    def _try_javascript_navigation(self, page_num: int) -> bool:
        """尝试使用JavaScript函数跳转"""
        try:
            # 检查函数是否存在
            func_exists = self.driver.execute_script("return typeof selectAllCourseFromStudent === 'function';")
            if not func_exists:
                logger.debug("selectAllCourseFromStudent 函数不存在")
                return False
            
            # 执行跳转
            self.driver.execute_script(f"selectAllCourseFromStudent({page_num});")
            time.sleep(2)
            
            # 验证跳转结果
            self._wait_for_page_ready(max_wait=10)
            current_page = self._get_current_page_number()
            
            if current_page == page_num:
                logger.debug("JavaScript 跳转成功")
                return True
            else:
                logger.debug(f"JavaScript 跳转未生效，当前页面: {current_page}")
                return False
                
        except Exception as e:
            logger.debug(f"JavaScript 跳转失败: {e}")
            return False
    
    def _try_click_navigation(self, page_num: int) -> bool:
        """尝试点击页面链接跳转"""
        try:
            logger.debug(f"尝试点击第 {page_num} 页链接...")
            
            # 查找对应的页面链接
            page_links = self.driver.find_elements(
                By.CSS_SELECTOR, 
                f"#page-box a[onclick*='selectAllCourseFromStudent({page_num})']"
            )
            
            if not page_links:
                logger.debug(f"未找到第 {page_num} 页的链接")
                return False
            
            target_link = page_links[0]
            
            # 滚动到元素可见
            self.driver.execute_script("arguments[0].scrollIntoView(true);", target_link)
            time.sleep(0.5)
            
            # 点击链接
            target_link.click()
            time.sleep(2)
            
            # 验证跳转结果
            self._wait_for_page_ready(max_wait=10)
            current_page = self._get_current_page_number()
            
            if current_page == page_num:
                logger.debug("点击跳转成功")
                return True
            else:
                logger.debug(f"点击跳转未生效，当前页面: {current_page}")
                return False
                
        except Exception as e:
            logger.debug(f"点击跳转失败: {e}")
            return False
    
    def _try_refresh_and_navigate(self, page_num: int) -> bool:
        """尝试刷新页面后重新跳转"""
        try:
            logger.debug("尝试刷新页面后重新跳转...")
            self.driver.refresh()
            time.sleep(3)
            self._wait_for_page_ready(max_wait=15)
            
            # 再次尝试JavaScript方法
            return self._try_javascript_navigation(page_num)
            
        except Exception as e:
            logger.debug(f"刷新后跳转失败: {e}")
            return False

    def _get_current_page_number(self) -> int:
        """获取当前页面页码"""
        try:
            # 方法1: 查找活跃的页面链接
            active_link = self.driver.find_element(By.CSS_SELECTOR, "#page-box .pg-link.active")
            page_text = active_link.text.strip()
            if page_text.isdigit():
                return int(page_text)
        except NoSuchElementException:
            pass
        
        # 方法2: 检查所有页面链接，找到没有onclick的（通常是当前页）
        try:
            page_links = self.driver.find_elements(By.CSS_SELECTOR, "#page-box .pg-link")
            for link in page_links:
                onclick = link.get_attribute('onclick')
                if not onclick and link.text.strip().isdigit():
                    return int(link.text.strip())
        except Exception:
            pass
        
        # 方法3: 从URL或页面状态获取
        try:
            # 这里可以添加更多的页码检测逻辑
            pass
        except Exception:
            pass
        
        return self._current_page if hasattr(self, '_current_page') else 1

    def _wait_for_page_ready(self, max_wait: int = 30) -> bool:
        """等待页面完全加载"""
        logger.debug("等待页面加载完成...")
        
        for i in range(max_wait):
            try:
                # 检查页面是否加载完成
                ready_state = self.driver.execute_script("return document.readyState")
                if ready_state == "complete":
                    # 等待课程列表加载
                    try:
                        WebDriverWait(self.driver, 3).until(
                            EC.presence_of_element_located((By.CLASS_NAME, "class-list"))
                        )
                        logger.debug("页面加载完成")
                        return True
                    except TimeoutException:
                        pass
                        
                time.sleep(1)
            except Exception:
                time.sleep(1)
        
        logger.warning(f"页面加载超时 ({max_wait}秒)")
        return False
    
    def get_current_page(self) -> int:
        """获取当前页码"""
        return self._current_page
    
    def get_total_pages(self) -> int:
        """获取总页数"""
        return self._total_pages
    
    def has_next_page(self) -> bool:
        """是否还有下一页"""
        return self._current_page < self._total_pages
    
    def has_previous_page(self) -> bool:
        """是否还有上一页"""
        return self._current_page > 1 